package edu.gatech.bsbmule.tests;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import java.awt.Color;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;

import org.junit.Before;
import org.junit.Test;

import edu.gatech.bsbmule.model.Game;
import edu.gatech.bsbmule.model.LandOffice;
import edu.gatech.bsbmule.model.Player;
import edu.gatech.bsbmule.model.Tile;

/**
 * This is the JUnit test case for testing sellTile() method in LandOffice class
 * Branches coverages are:
 * Tile is a town
 * Tile is owned by other players
 * Current round is free land phase and it is the first time a player gets a free tile during this round
 * Current round is free land phase but it is not the first time a player gets a free tile during this round
 * Current round is not free land phase and player can afford the tile
 * Current round is not free land pahse but player cannot afford the tile
 *
 * @author Hanjie
 *
 */
public class TestByHanjie {
	Game game;
	Player rich;
	Player poor;
	Tile testedTile;
	LandOffice lo;
	
	@Before
	public void init() {
		game = Game.getInstance();
		rich = new Player("rich", Color.WHITE, Player.RACE_HUMAN, 1000, 1000, 1000, 1000);
		poor = new Player("poor", Color.WHITE, Player.RACE_HUMAN, 0, 1000, 1000, 1000);
		List<Player> players = new ArrayList<Player>();
		players.add(rich);
		players.add(poor);
		game.setPlayers(players);
		lo = new LandOffice();
	}
	
	@Test
	public void testByTownTile() {
		testedTile = new Tile(Tile.TERRAIN_TOWN, new Point(0, 0));
		boolean townTileSold = lo.sellTile(rich, testedTile);
		assertFalse("Town tile should not be sold", townTileSold);
		boolean ownershipChanged = rich.isOwnedTile(testedTile);
		assertFalse("Ownership should not be changed if tile is town", ownershipChanged);
	}
	
	@Test
	public void testByOwnedTile() {
		testedTile = new Tile(Tile.TERRAIN_PLAIN, new Point(0, 0));
		poor.addOwnedTile(testedTile);
		boolean ownedTileSold = lo.sellTile(rich, testedTile);
		assertFalse("Owned tile should not be sold", ownedTileSold);
		boolean ownershipChanged = rich.isOwnedTile(testedTile);
		assertFalse("Ownership should not be changed if tile is owned by others", ownershipChanged);
	}
	
	@Test
	public void testDuringLandGrantAndFirstTimeFreeLand() {
		testedTile = new Tile(Tile.TERRAIN_PLAIN, new Point(0, 0));
		game.setCurrentRound(2);
		rich.setFirstTimeFreeLand(true);
		int previousMoney = rich.getMoney();
		boolean freeTileSold = lo.sellTile(rich, testedTile);
		assertTrue("Transaction should be successful if tile is availible during land grant phase", freeTileSold);
		int afterMoney = rich.getMoney();
		boolean moneySubtracted = (previousMoney > afterMoney);
		assertFalse("Money should not be subtracted if selling tile during land grant phase", moneySubtracted);
		boolean ownershipChanged = rich.isOwnedTile(testedTile);
		assertTrue("Ownership should be changed if tile is availible during land grant phase", ownershipChanged);
	}
	
	@Test
	public void testDuringLandGrantButNotFirstTimeFreeLand() {
		testedTile = new Tile(Tile.TERRAIN_PLAIN, new Point(0, 0));
		game.setCurrentRound(2);
		rich.setFirstTimeFreeLand(false);
		boolean freeTileSold = lo.sellTile(rich, testedTile);
		assertFalse("Transaction should not be successful if tile is availible during land grant phase but it is not the first time a player gets a free tile", freeTileSold);
		boolean ownershipChanged = rich.isOwnedTile(testedTile);
		assertFalse("Ownership should not be changed if tile is availible during land grant phase but it is not the first time a player gets a free tile", ownershipChanged);
	}
	
	@Test
	public void testDuringNormalAndPlayerCanAfford() {
		testedTile = new Tile(Tile.TERRAIN_PLAIN, new Point(0, 0));
		game.setCurrentRound(3); // During round 3 the maximum random price a tile can generate is 600 so the rich player can definitely afford a tile
		int previousMoney = rich.getMoney();
		boolean tileSold = lo.sellTile(rich, testedTile);
		assertTrue("Transaction should be successful if player can afford the tile", tileSold);
		int afterMoney = rich.getMoney();
		boolean moneySubtracted = (previousMoney > afterMoney);
		assertTrue("Money should be subtracted if player can afford the tile", moneySubtracted);
		boolean ownershipChanged = rich.isOwnedTile(testedTile);
		assertTrue("Ownership should be changed if player can afford the tile", ownershipChanged);
	}
	
	@Test
	public void testDuringNormalButPlayerCannotAfford() {
		testedTile = new Tile(Tile.TERRAIN_PLAIN, new Point(0, 0));
		game.setCurrentRound(3);
		int previousMoney = poor.getMoney();
		boolean tileSold = lo.sellTile(poor, testedTile);
		assertFalse("Transaction should not be successful if player cannot afford the tile", tileSold);
		int afterMoney = poor.getMoney();
		boolean moneySubtracted = (previousMoney > afterMoney);
		assertFalse("Money should not be subtracted if player cannot afford the tile", moneySubtracted);
		boolean ownershipChanged = poor.isOwnedTile(testedTile);
		assertFalse("Ownership should not be changed if player cannot afford the tile", ownershipChanged);
	}
}
